#!/usr/bin/python
# server1,640,/path/to/scripts/to/run/,/path/to/scripts/output/,SERVER_TYPE=dev::server2,630,/path/to/scripts/to/run/,/path/to/scripts/output/,SERVER_TYPE=gen
import os
import ast
import sys
import glob
import time
import atexit
import argparse
import requests
from pyVmomi import vim, vmodl
from pyVim import connect
from pysphere import VIServer
from multiprocessing import Process
from pysphere.resources import VimService_services as VI
from pyVim.connect import Disconnect, SmartConnect, GetSi


# Examples:
# build-a-box.py server1,640
# build-a-box.py server1,640,,,SERVER_TYPE=gen
# build-a-box.py server3,640::xldn6683vnap,630::xldn6682vnap,580
# build-a-box.py server1,640,/path/to/scripts/to/run/,/path/to/scripts/output/,SERVER_TYPE=dev::server2,630,/path/to/scripts/to/run/,/path/to/scripts/output/,SERVER_TYPE=gen

# Set variables

try:
    if not sys.argv[1]:
       print "Here are a few examples:"
       print "build-a-box.py server1,640"
       print "build-a-box.py server1,640,,,SERVER_TYPE=gen"
       print "build-a-box.py xldn6681vnap,640::server1,630::server2,580"
       print "build-a-box.py server1,640,/path/to/scripts/to/run/,/path/to/scripts/output/,SERVER_TYPE=dev::server2,630,/path/to/scripts/to/run/,/path/to/scripts/output/,SERVER_TYPE=gen"
       sys.exit()
except Exception as e:
       print "Here are a few examples:"
       print "build-a-box.py server1,640"
       print "build-a-box.py server2,640,,,SERVER_TYPE=gen"
       print "build-a-box.py xldn6681vnap,640::server2,630::server1,580"
       print "build-a-box.py server1,640,/path/to/scripts/to/run/,/path/to/scripts/output/,SERVER_TYPE=dev::server2,630,/path/to/scripts/to/run/,/path/to/scripts/output/,SERVER_TYPE=gen"
       sys.exit()
HOSTNAME_VARS = sys.argv[1].strip()
keypass       = eval(open('/home/auth.txt','r').read())
jss_user      = keypass['jss_user'][0]
jss_pass      = keypass['jss_pass'][0]
#Change the below server to a vcenter that suites you
vcenter       = "nldn9995nap"
vuser         = keypass['vcenter_user'][0]
vpass         = keypass['vcenter_password'][0]
guest_user    = keypass['guest_user'][0]
guest_pass    = keypass['guest_pass'][0]


# Builds that may need to be built

OS_RELS = {
'530':{'OS_ALIAS':'531'},
'550':{'OS_ALIAS':'551 x86 64bit'},
'580':{'OS_ALIAS':'580 x86 64bit'},
'620':{'OS_ALIAS':'620 x86 64bit'},
'630':{'OS_ALIAS':'632 x86 64bit'},
'640':{'OS_ALIAS':'640 x86 64bit'},
'660':{'OS_ALIAS':'660 x86 64bit'}
}


PAY_LOAD = {
'BOB'            : "prod",
'SERVER_TYPE'    : "gen",
'PASSWORD'       : str(jsspass),
'REQTYPE'        : "jssprime",
'LOGIN'          : str(user),
'USE_SSO'        : "yes",
'JSSHOME'        : "/dev/",
'HARDWARE_ALIAS' : "VMware"
}


### Run SCRIPTS CODE ###


def vsr(sysArray,scriptsIn,scriptsOut):

  #Sleep a couple of secs to make sure system is rebooting
  time.sleep(20)
  def returnList(scriptList):
    return scriptList.split(",")

  def returnScriptList(sList):
    getAll="*"
    if sList[-1] != "/":
        sList = sList + "/"
    lscripts = glob.glob(sList + getAll)
    return lscripts

# This function checks if a process is finished and gets the log file

  def checkGetDone(systemName, scriptName, LogFilePathName, pId, outdir):
    gotFile = False
    vm = server.get_vm_by_name((systemName).strip())
    vm.login_in_guest(GUESTUSER,GUESTPASS)
    while not gotFile:
        allProcs = vm.list_processes()
        myProc = [i for i in allProcs if str(i['pid']).strip() == str(pId).strip()]
        if str(myProc[0]['exit_code']).strip() != "None":
            vm.get_file(LogFilePathName.strip(), outdir + systemName + "-" + scriptName + "-log", overwrite=True)
            vm.start_process("/bin/rm", args=["-rf",LogFilePathName.strip()])
            gotFile = True
        else:
            time.sleep(10)

  def runScripts(VARS):

    vars = VARS
    systms = vars['SYSNAMES']
    server = VIServer()
    server.connect(VARS['VMWAREESXSERVER'],ESXUSER,ESXPASSWD)

    try:
        vm = server.get_vm_by_name(str(systms).strip())
    except Exception as e:
        print "vCenter Error: %s error: %s" %(VARS['VMWAREESXSERVER'],e)

    count = 0
    for i in range(60):
        count = count + 1
        try:
            vm.login_in_guest(GUESTUSER,GUESTPASS)
            if vm.list_files("/var/install/",match_pattern="hook.log"):
                print "%s up, took %s minutes to build, running scripts" %(systms, count)
                break
            else:
                time.sleep(60)
                sys.stdout.flush()
        except Exception as e:
            time.sleep(60)
            sys.stdout.flush()
            pass

    try:
        vm.make_directory(VARS['VMWARETMPDIR'],create_parents=True)
    except Exception as e:
        pass

    print "Starting script run!"
    VARS['SCRIPT2RUN'] = vars['SCRIPT2RUN']
    VARS['VMWARETMPDIR'] = vars['VMWARETMPDIR']
    server = VIServer()
    server.connect(VARS['VMWAREESXSERVER'],ESXUSER,ESXPASSWD)
    vm = server.get_vm_by_name(str(systms).strip())
    for script in glob.glob(VARS['SCRIPT2RUN'] + "*"):
        SCRIPT         = script.split("/")[-1]
        PATH2SCRIPT    = VARS['VMWARETMPDIR'] + SCRIPT
        PATH2SCRIPTLOG = VARS['VMWARETMPDIR'] + SCRIPT + "-log"
        vm.login_in_guest(GUESTUSER,GUESTPASS)
        vm.send_file(script, PATH2SCRIPT, overwrite=True)
        vm.start_process("/bin/chmod",args=['a+rx',PATH2SCRIPT])
        vm.start_process("/bin/ln",args=['-s','/lib64/security/pam_unix.so','/lib64/security/pam_unix2.so'])
        pid = vm.start_process(PATH2SCRIPT,env={'OUTPUT':PATH2SCRIPTLOG})
        checkGetDone(systms, SCRIPT, PATH2SCRIPTLOG, pid, outdir)


# Set Variables

# arg1 is a comma separated list of servers
# arg2 is path to a directory full of scripts to run on the clients

  #systems   = returnList(sys.argv[1])
  systems   = sysArray
  scripts   = scriptsIn
  outdir    = scriptsOut

  GUESTUSER = guest_user
  GUESTPASS = guest_pass
  ESXUSER   = vuser
  ESXPASSWD = vpass
  isDone    = False

  VARS      = {

'SYSNAMES'        : systems,
'VMWAREESXSERVER' : vcenter,    # Currently only works for ldn, need to fix this
'VMWARETMPDIR'    : '/var/3rd/',
'VMWAREOUTPUTLOG' : 'vmoutput.log',
'SCRIPT2RUN'      : scripts

}

# Connect to ESX Server

  server = VIServer()
  server.connect(VARS['VMWAREESXSERVER'],ESXUSER,ESXPASSWD)

# Run list of scripts on list of servers, should probably put this in a function

  p = Process(target=runScripts,args=(VARS,))
  p.start()


### BOOT FROM NETWORK CODE ###

def bootFromNetwork(systemName):

# NB: These can be adjusted if you choose for different regions
  system = systemName
  inputs = {'vcenter_ip': vcenter,
          'vcenter_password': str(vpass),
          'vcenter_user': str(vuser),
          'vm_name' : system,
          'operation' : 'stop',
          'force' : True,
          }

  def get_obj(content, vimtype, name):
    """
     Get the vsphere object associated with a given text name
    """
    obj = None
    container = content.viewManager.CreateContainerView(content.rootFolder, vimtype, True)
    for c in container.view:
        if c.name == name:
            obj = c
            break
    return obj

  def wait_for_task(task, actionName='job', hideResult=True):
    """
    Waits and provides updates on a vSphere task
    """

    while task.info.state == vim.TaskInfo.State.running:
        time.sleep(2)

    if task.info.state == vim.TaskInfo.State.success:
        if task.info.result is not None and not hideResult:
            out = '%s completed successfully, result: %s' % (actionName, task.info.result)
        else:
            out = '%s completed successfully.' % actionName
    else:
        out = '%s did not complete successfully: %s' % (actionName, task.info.error)
        raise task.info.error
    return task.info.result

  si = connect.Connect(inputs['vcenter_ip'], 443, inputs['vcenter_user'], inputs['vcenter_password'])
  content = si.RetrieveContent()
  vm = get_obj(content, [vim.VirtualMachine], inputs['vm_name'])
  vm.PowerOff()


# Set to boot from network

  bn                  = vim.option.OptionValue(key='bios.bootDeviceClasses',value='allow:net')
  vmconf              = vim.vm.ConfigSpec()
  vmconf.extraConfig  = [bn]
  task  = vm.ReconfigVM_Task(vmconf)
  wait_for_task(task,si)
  task1 = vm.PowerOnVM_Task()
  wait_for_task(task1,si)

# Set system to boot from hdd again
  time.sleep(15)
  bn                  = vim.option.OptionValue(key='bios.bootDeviceClasses',value='allow:hd,cd,fd,net')
  vmconf              = vim.vm.ConfigSpec()
  vmconf.extraConfig  = [bn]
  vm.ReconfigVM_Task(vmconf)


### Where the actual building takes place


for jobs in HOSTNAME_VARS.split("::"):
    PAY_LOAD['HOSTNAME'] = jobs.split(",")[0]
    SC_URL = "https://jssdev." + str(PAY_LOAD['HOSTNAME'][1:4]) + ":443/jss-proxy"
    PAY_LOAD['OS_ALIAS'] = OS_RELS[jobs.split(",")[1]]['OS_ALIAS']
    try:
       if jobs.split(",")[4:][0]:
          if jobs.split(",")[4:][0] != "":
             for vars in jobs.split(",")[4:]:
                key,value = vars.split("=")
                PAY_LOAD[key] = value
    except Exception as e:
       pass
    try:
        print "\nRunning SC for %s... " %PAY_LOAD['HOSTNAME'],
        r = requests.get(SC_URL,params=PAY_LOAD, verify=False)
        if r.text[:3] != "200":
           print "Something borked with: %s\nOutput: %s" %(PAY_LOAD['HOSTNAME'], r.text)
        else:
           print " Done!"
           print "Booting %s boot from network... " %PAY_LOAD['HOSTNAME'],
           pr = Process(target=bootFromNetwork,args=(PAY_LOAD['HOSTNAME'],))
           pr.start()
           print " Done!"
           try:
               if jobs.split(",")[2] and jobs.split(",")[3]:
                   print "Setting runscripts on first boot...",
                   vsr(PAY_LOAD['HOSTNAME'],jobs.split(",")[2],jobs.split(",")[3])
                   print " NB: Command will wait until the builds and scripts are complete, coffee?\n"
           except Exception as e:
               pass
    except Exception as e:
        print "Issue with server: %s\nError: %s" %(PAY_LOAD['HOSTNAME'], e)


